<?php
namespace App\Admin\Export;

class BaseExport {

    public function csv_export($fileName, $headList=array(), $data=array()){

        //为临时修改配置，脚本运行时保持新的值，并在脚本结束时恢复
        set_time_limit(0);//设置脚本最大执行时间,单位为S，默认30S；如果设置为0，没有时间方面的限制
        ini_set('memory_limit','1024M');//默认128M

        //设置头部信息，但是在设置之前，不能有任何实际输出。不管是普通的 HTML 标签，还是文件或 PHP 输出的空行，空格
        header('Cache-Control: public');
        header('Pragma: public');
        header('Content-type:application/vnd.ms-excel');
        header('Content-Disposition:attachment;filename=' . $fileName);
        header('Content-Type:application/octet-stream');

        ob_start();// 打开输出控制缓冲

        $fp = fopen('php://output','a');//a:写入模式打开文件，并将指针指向文件末尾，文件不存在创建；此时打开的可以是具体的文件地址，也可以是scheme://...格式，php可以使用封装协议来处理此模式

        //整理Excel列名信息
        foreach ($headList as $key => $value) {
            //CSV的Excel支持GBK编码，一定要转换，否则乱码
            $headList[$key] = iconv('utf-8', 'gbk', $value);
        }
        fputcsv($fp, $headList);//将行格式化为CSV，并写入文件指针，前一步创建文件时，指针指向末尾，那该方法就是将数据追加到文件中


        $num = 0;//计数器
        $limit = 100000; //每隔$limit行，刷新一下输出buffer，不要太大，也不要太小

        //为了防止内存溢出，逐行取出数据，不浪费内存
        $count = count($data);
        for ($i = 0; $i < $count; $i++) {

            $num++;

            //刷新一下输出buffer，防止由于数据过多造成问题
            if ($limit == $num) {
                ob_flush();//每一次循环结束，将循环放入缓冲区的数据，送出输出缓冲区
                flush();//刷新输出缓冲，flush() 函数不会对服务器或客户端浏览器的缓存模式产生影响。因此，必须同时使用ob_flush（）来刷新输出缓冲
                $num = 0;
            }

            $row = $data[$i];
            foreach ($row as $key => $value) {
                $row[$key] = iconv('utf-8', 'gbk', $value);//修改数据
            }

            fputcsv($fp, $row);// 将每一行获取到的并整理好的数据追加到输出缓冲区内
        }


        ob_end_flush(); //输出缓冲区内容并关闭缓冲区（销毁输出缓冲区）
        fclose($fp);
    }
}
